/*
struct o {
  int x;
  int y;
  int z;
  int dbId;
}

#define DIST(a,b) ((((struct o)a).x-       \
		    ((struct o)b).x)**2 +  \
		   (((struct o)a).y-       \
		    ((struct o)b).y)**2 +  \
		   (((struct o)a).z-       \
		    ((struct o)b).z)**2)
*/   
#include "../bulk_storage/bulk_storage.h"
#include "../metric/xyz.h"
#include "mTree.h"
#include <stdlib.h>
#include <sys/timeb.h>
#include <assert.h>
#define SIZE 10000
//#define QUERIES 1458 * 100
#define QUERIES 100

#define READ_POINTS


//#define MUL_POINTS

struct xyz_int queryObjects[1458];

int main () {
  unsigned short start, middle, stop, end_verify;
  struct timeb ts;
  struct xyz_int objs;
  int count = 0;
  // int i;
  int cacheSize = 5000;


#ifdef READ_POINTS

  float x, y, z;
  int i = 0;
  //  objs.i = 0;
  while(scanf("%f\t%f\t%f\n", &x, &y, &z) != EOF) {
    //    int i;
    objs.x = (int)(x*100);
    objs.y = (int)(y*100);
    objs.z = (int)(z*100);
    i++;
    //    objs.i++;
    queryObjects[i-1].x = objs.x;
    queryObjects[i-1].y = objs.y;
    queryObjects[i-1].z = objs.z;
    //    queryObjects[objs.i-1].i = objs.i;
    
    //    printf("%d:%d:%d\n", objs.x, objs.y,objs.z);
    //    mTree_insert(tree, &objs);
    
    
    /*#ifdef MUL_POINTS
    
    for(i = 0; i < 1000; i++) {
      objs.x += 1;
      objs.y += 1;
      objs.z += 1;
      //      mTree_insert(tree, &objs);
    }
    
 #endif
    */
  }
#endif
  

  for(count = 0; count < 12; count++) {
    //struct mTree* tree = mTree_new_memory(sizeof(int[4]));

    /*    struct mTree* tree = mTree_new_cached("store_mTree_o", "store_mTree_o.fat", "store_mTree_n", "store_mTree_n.fat",	sizeof(int[4]), cacheSize, (double(*)(void*,void*))&xyzi_dist); */
    struct store* oStore = store_open_cached("store_mTree_o", "store_mTree_o.fat", sizeof(int[4]), 100, cacheSize);
    struct mTree* tree = mTree_open_cached(oStore, "store_mTree_n", "store_mTree_n.fat", cacheSize, (double(*)(const void*,const void*))&xyz_int_distance);
    int i;
    cacheSize/=2;
    
    mTree_verify(tree);
    printf("Size after opening = %d\n", (int)mTree_size(tree));
    //  int dist = DIST(object, other);
    
    printf ("Helloasdasd\n");
    
      ftime(&ts);
      start = ts.time;
#ifndef READ_POINTS
  struct xyz_int * objs_ptr;
      for(i = 0; i < SIZE; i++) {
	off_t storeNumber;
	objs.x = (int)(1.0 * rand()/(RAND_MAX+1.0));
	objs.y = (int)(1.0 * rand()/(RAND_MAX+1.0));
	objs.z = (int)(1.0 * rand()/(RAND_MAX+1.0));
	//	objs.i = i;
       	//cs_checkForLeaksAndFlush(tree->nStore->store);
	storeNumber = store_new(oStore);
	objs_ptr = store_read(oStore, storeNumber);
	objs_ptr->x = objs.x;
	objs_ptr->y = objs.y;
	objs_ptr->z = objs.z;
	//	objs_ptr->i = objs.i;

	store_write(oStore, storeNumber);
	mTree_insert(tree, storeNumber);
	store_release(oStore, storeNumber);

	//cs_checkForLeaksAndFlush(tree->nStore->store);


      }
#endif
#ifdef READ_POINTS
      //      objs.i = 0;
      /*      while(scanf("%f\t%f\t%f\n", &x, &y, &z) != EOF) {
	
	objs.x = (int)(x*100);
	objs.y = (int)(y*100);
	objs.z = (int)(z*100);
	objs.i++;
	queryObjects[objs.i-1].x = objs.x;
	queryObjects[objs.i-1].y = objs.y;
	queryObjects[objs.i-1].z = objs.z;
	queryObjects[objs.i-1].i = objs.i;
      */
      for(i = 0; i < 1458; i++) {
	//    printf("%d:%d:%d\n", objs.x, objs.y,objs.z);
	off_t storeNumber = store_new(oStore);
	struct xyz_int * qo_ptr = store_read(oStore, storeNumber);
	qo_ptr->x = queryObjects[i].x;
	qo_ptr->y = queryObjects[i].y;
	qo_ptr->z = queryObjects[i].z;
	//	qo_ptr->i = queryObjects[i].i;
	store_write(oStore, storeNumber);
	store_release(oStore, storeNumber);

	mTree_insert(tree, storeNumber);

      }	
	
      /*#ifdef MUL_POINTS
	
      for(i = 0; i < 1000; i++) {
      objs.x += 1;
      objs.y += 1;
      objs.z += 1;
      mTree_insert(tree, &objs);
	  }
	
	#endif*/
	
  
#endif
      
      printf("Done!\n");
      ftime(&ts);
      middle = ts.time;
      
      //      mTree_print(tree);
      
      for(i = 0; i < QUERIES; i++) {
#ifndef READ_POINTS

	int j = (int)(1000.0 * rand()/(RAND_MAX+1.0));
	objs.x =(int)(10000.0 * rand()/(RAND_MAX+1.0));
	objs.y =(int)(10000.0 * rand()/(RAND_MAX+1.0));
	objs.z =(int)(10000.0 * rand()/(RAND_MAX+1.0));
	//	objs.i = i;
	mTree_rangeQuery(tree, &objs, j, &xyz_int_print, stdout);
#endif
#ifdef READ_POINTS
	
	objs.x = queryObjects[i % 1458].x;
	objs.y = queryObjects[i % 1458].y;
	objs.z = queryObjects[i % 1458].z;
	//	objs.i = queryObjects[i % 1458].i;
	mTree_rangeQuery(tree, &objs, 10,  ( void (*)(void*, void*) )&xyz_int_print, stdout);

#endif    

      }
      ftime(&ts);
      stop = ts.time;

      //      mTree_print(tree);
      //      mTree_verify(tree);

      ftime(&ts);
      end_verify = ts.time;
      //      mTree_print(tree);
      
      printf("<-- mem store | cache store -->\n");
      cs_print(tree->oStore->store_p);
      
      printf("Tree Size: %ld\n", (long int)mTree_size(tree));
      printf("Times: build - %d query - %d verify - %d\n", (middle-start), (stop-middle), (end_verify - stop));
      mTree_close(tree);
      store_close(oStore);
  }

  return 0;
}
